package cn.lg.soar.common.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: luguoxiang
 * @Date: 2021-06-04 11:52
 * @Description: 异常工具
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public interface ExceptionUtil {

    /**
     * 格式化异常信息
     * @param e
     * @return
     */
    static String formatException(Throwable e){
        StringBuilder sb = new StringBuilder();
        sb.append(e.getClass().getName())
                .append(": ")
                .append(e.getMessage())
                .append("\n");
        StackTraceElement[] elements = e.getStackTrace();
        for (StackTraceElement element : elements) {
            sb.append(element.getClassName())
                    .append(": ")
                    .append(element.getLineNumber())
                    .append("\n");
        }
        return sb.toString();
    }

    // 精简后的最大堆栈深度
    int MAX_STACK_TRACE_DEPTH = 15;

    // 常见需要过滤的包前缀（非业务相关）
    List<String> EXCLUDE_PACKAGE_PREFIXES = List.of(
            "java.lang.reflect.",
            "sun.reflect.",
            "jdk.internal.reflect.",
            "org.springframework.",
            "java.util.concurrent.",
            "org.apache.catalina.",
            "org.apache.tomcat.",
            "org.jboss."
    );

    /**
     * 获取精简后的异常堆栈字符串
     * @param throwable 异常对象
     * @param limit 最大显示帧数
     * @return 精简后的堆栈字符串
     */
    static String getRefinedStackTrace(Throwable throwable, int limit) {
        // 过滤掉常见的非业务相关堆栈帧
        List<StackTraceElement> filtered = Arrays.stream(throwable.getStackTrace())
                .filter(element ->
                        !element.getClassName().startsWith("java.lang.reflect.") &&
                                !element.getClassName().startsWith("sun.reflect.") &&
                                !element.getClassName().startsWith("org.springframework.aop.") &&
                                !element.getClassName().startsWith("org.springframework.web.servlet.") &&
                                !element.getClassName().startsWith("org.springframework.context.support.") &&
                                !element.getClassName().startsWith("jdk.internal.reflect.") &&
                                !element.getClassName().startsWith("java.util.concurrent.")
                )
                .limit(limit) // 控制最大显示帧数，避免过长
                .collect(Collectors.toList());

        return formatStackTrace(filtered);
    }

    /**
     * 格式化堆栈为字符串
     */
    private static String formatStackTrace(List<StackTraceElement> elements) {
        StringBuilder sb = new StringBuilder();
        for (StackTraceElement element : elements) {
            sb.append("\n\tat ").append(element.toString());
        }
        return sb.length() > 0 ? sb.substring(1) : ""; // 去掉第一个换行符
    }

}
